package cluster

import (
	"fmt"
	"time"
)

// ClusterConfig represents the configuration for a cluster node
type ClusterConfig struct {
	// NodeID is the unique identifier for this node
	NodeID string
	// NodeName is the human-readable name for this node
	NodeName string
	// BindAddress is the address to bind to for cluster communication
	BindAddress string
	// BindPort is the port to bind to for cluster communication
	BindPort int
	// AdvertiseAddress is the address to advertise to other nodes
	AdvertiseAddress string
	// AdvertisePort is the port to advertise to other nodes
	AdvertisePort int
	// SeedNodes is a list of seed nodes to join
	SeedNodes []string
	// ClusterName is the name of the cluster
	ClusterName string
	// HeartbeatInterval is the interval between heartbeats
	HeartbeatInterval time.Duration
	// MonitorInterval is the interval between monitoring checks
	MonitorInterval time.Duration
	// MaxJoinAttempts is the maximum number of join attempts
	MaxJoinAttempts int
	// JoinRetryInterval is the interval between join attempts
	JoinRetryInterval time.Duration
	// StabilizationTime is the time to wait for cluster stabilization
	StabilizationTime time.Duration
	// Tags is a map of tags to associate with this node
	Tags map[string]string
}

// NewDefaultClusterConfig creates a new default cluster configuration
func NewDefaultClusterConfig() *ClusterConfig {
	return &ClusterConfig{
		BindAddress:       "127.0.0.1",
		BindPort:          7946,
		AdvertiseAddress:  "127.0.0.1",
		AdvertisePort:     7946,
		ClusterName:       "dataflare-cluster",
		HeartbeatInterval: 1 * time.Second,
		MonitorInterval:   5 * time.Second,
		MaxJoinAttempts:   3,
		JoinRetryInterval: 5 * time.Second,
		StabilizationTime: 10 * time.Second,
		Tags:              make(map[string]string),
	}
}

// Validate validates the cluster configuration
func (c *ClusterConfig) Validate() error {
	if c.BindAddress == "" {
		return fmt.Errorf("bind address is required")
	}
	if c.BindPort <= 0 {
		return fmt.Errorf("bind port must be greater than 0")
	}
	if c.ClusterName == "" {
		return fmt.Errorf("cluster name is required")
	}
	return nil
}

// GetBindAddress returns the full bind address (host:port)
func (c *ClusterConfig) GetBindAddress() string {
	return fmt.Sprintf("%s:%d", c.BindAddress, c.BindPort)
}

// GetAdvertiseAddress returns the full advertise address (host:port)
func (c *ClusterConfig) GetAdvertiseAddress() string {
	addr := c.AdvertiseAddress
	if addr == "" {
		addr = c.BindAddress
	}
	port := c.AdvertisePort
	if port <= 0 {
		port = c.BindPort
	}
	return fmt.Sprintf("%s:%d", addr, port)
}
